package com.benyanyi.basicview.progress;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.benyanyi.basicview.DisplayUtils;
import com.benyanyi.basicview.R;

import java.text.DecimalFormat;

/**
 * @author yanyi
 * @date 2018/8/17 14:38
 * @email ben@yanyi.red
 * @overview 圆环进度条
 */
public class CircleProgress extends View {
    /**
     * 上下文
     */
    private Context mContext;
    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 中间圆背景
     */
    private Paint rPaint;
    private int rColor = Color.parseColor("#00ffffff");
    /**
     * 背景画笔
     */
    private Paint bPaint;
    private int[] colors = new int[]{Color.parseColor("#00ff00"), Color.parseColor("#ffff00"), Color.parseColor("#ff0000")};
    /**
     * 最大值
     */
    private float maxSize;
    /**
     * 最小值
     */
    private float minSize;
    /**
     * 当前值
     */
    private float size;
    /**
     * 当前值
     */
    private float number;

    /**
     * 计算当前值对应的角度
     */
    private float mSweepAngle;
    /**
     * 开始位置
     */
    private float startAngle;
    /**
     * 圆环的范围
     */
    private float angle;
    /**
     * 一份所占的角度
     */
    private float proportion;
    /**
     * 中间显示的文字
     */
    private TextView tv;
    /**
     * 显示时的值
     */
    private float msgSize;
    private int dip;
    /**
     * 是否让进度条渐变，默认渐变
     */
    private boolean isShader;
    /**
     * 圆环画笔默认颜色
     */
    private int defaultColor;
    /**
     * 圆环画笔线宽
     */
    private float defaultWidth;
    /**
     * 背景圆环颜色
     */
    private int bgColor;
    /**
     * 背景圆环线宽
     */
    private float bgWidth;
    /**
     * 左边文字
     */
    private String leftMsg;
    /**
     * 右边文字
     */
    private String rightMsg;
    /**
     * 显示小数位
     */
    private boolean isDecimal;
    /**
     * 是否等边
     */
    private boolean isEquilateral;

    private float proportionSize = 0;

    private boolean isRefresh = true;

    private int mWidth = -2;
    private int mHeight = -2;

    private int mPadding = 0;
    private int mPaddingLeft = 0;
    private int mPaddingRight = 0;
    private int mPaddingTop = 0;
    private int mPaddingBottom = 0;


    public CircleProgress(Context context) {
        this(context, null);
    }

    public CircleProgress(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.CircleProgress, defStyleAttr, 0);
        try {
            maxSize = ta.getFloat(R.styleable.CircleProgress_cpMaxSize, 100);
            minSize = ta.getFloat(R.styleable.CircleProgress_cpMinSize, 0);
            startAngle = ta.getFloat(R.styleable.CircleProgress_cpStartAngle, 180);
            angle = ta.getFloat(R.styleable.CircleProgress_cpAngle, 360);
            isShader = ta.getBoolean(R.styleable.CircleProgress_cpIsShader, true);
            rColor = ta.getColor(R.styleable.CircleProgress_cpRoundColor, rColor);
            defaultColor = ta.getColor(R.styleable.CircleProgress_cpDefaultColor, Color.RED);
            defaultWidth = ta.getDimension(R.styleable.CircleProgress_cpDefaultWidth, 16);
            bgColor = ta.getColor(R.styleable.CircleProgress_cpBgColor, Color.GRAY);
            bgWidth = ta.getDimension(R.styleable.CircleProgress_cpBgWidth, 16);
            leftMsg = ta.getString(R.styleable.CircleProgress_cpLeftMsg);
            rightMsg = ta.getString(R.styleable.CircleProgress_cpRightMsg);
            isDecimal = ta.getBoolean(R.styleable.CircleProgress_cpIsDecimal, true);
            isEquilateral = ta.getBoolean(R.styleable.CircleProgress_cpEquilateral, false);
            mWidth = ta.getLayoutDimension(R.styleable.CircleProgress_android_layout_width, mWidth);
            mHeight = ta.getLayoutDimension(R.styleable.CircleProgress_android_layout_height, mHeight);
            mPadding = ta.getLayoutDimension(R.styleable.CircleProgress_android_padding, mPadding);
            if (mPadding == 0) {
                mPaddingLeft = ta.getLayoutDimension(R.styleable.CircleProgress_android_paddingLeft, mPaddingLeft);
                mPaddingRight = ta.getLayoutDimension(R.styleable.CircleProgress_android_paddingRight, mPaddingRight);
                mPaddingTop = ta.getLayoutDimension(R.styleable.CircleProgress_android_paddingTop, mPaddingTop);
                mPaddingBottom = ta.getLayoutDimension(R.styleable.CircleProgress_android_paddingBottom, mPaddingBottom);
            }
            size = minSize;
            number = minSize;
            msgSize = minSize;
            //计算值为1时所占角度的大小
            proportion = angle / (maxSize - minSize);
            proportionSize = maxSize / 60;
            setPaint();
        } finally {
            ta.recycle();
        }

    }

    /**
     * 设置画笔
     */
    private void setPaint() {
        //设置进度条画笔
        mPaint = new Paint();
        //设置画笔颜色
        mPaint.setColor(defaultColor);
        //设置画笔无锯齿
        mPaint.setAntiAlias(true);
        //线宽
        mPaint.setStrokeWidth(defaultWidth);
        //只绘制轮廓
        mPaint.setStyle(Paint.Style.STROKE);
        //设置圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        //设置背景画笔
        bPaint = new Paint();
        //设置画笔颜色
        bPaint.setColor(bgColor);
        //设置画笔无锯齿
        bPaint.setAntiAlias(true);
        //线宽
        bPaint.setStrokeWidth(bgWidth);
        //只绘制轮廓
        bPaint.setStyle(Paint.Style.STROKE);
        //设置圆角
        bPaint.setStrokeCap(Paint.Cap.ROUND);
        //设置中间圆画笔
        rPaint = new Paint();
        //设置画笔颜色
        rPaint.setColor(rColor);
        //设置画笔无锯齿
        rPaint.setAntiAlias(true);
        //线宽
        rPaint.setStrokeWidth(1);
        //只绘制轮廓
        rPaint.setStyle(Paint.Style.FILL);
        dip = DisplayUtils.dip2px(mContext, 20);
    }

    /**
     * //绘制渐变
     * //        Shader sweepGradient = new SweepGradient(getWidth() / 2, getHeight() / 2, colors, null);
     * //        mPaint.setShader(sweepGradient);
     *
     * @param canvas
     */
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        float x0 = bgWidth / 2 + mPadding + mPaddingLeft;
        float y0 = bgWidth / 2 + mPadding + mPaddingTop;

        float x1 = mWidth - bgWidth / 2 - mPadding - mPaddingRight;
        float y1 = mHeight - bgWidth / 2 - mPadding - mPaddingBottom;

        if (isShader) {
            LinearGradient mGradient = new LinearGradient(x0, y0, x1, y1, colors, null, LinearGradient.TileMode.CLAMP);
            mPaint.setShader(mGradient);
        }
        RectF rectF = new RectF(x0, y0, x1, y1);
        //中间椭圆背景的椭圆对象，开始角度，圆弧角度，是否与圆心连线，画笔
        canvas.drawArc(rectF, startAngle, angle, false, rPaint);
        //圆弧所在范围的外矩形
        rectF = new RectF(x0, y0, x1, y1);
        //背景圆弧所在的椭圆对象，开始角度，圆弧角度，是否与圆心连线，画笔
        canvas.drawArc(rectF, startAngle, angle, false, bPaint);
        //圆弧所在的椭圆对象，开始角度，圆弧角度，是否显示连线（圆弧两边与圆心的连线）,画笔
        canvas.drawArc(rectF, startAngle, mSweepAngle, false, mPaint);
        Log.v("进度角度", mSweepAngle + "");
//        float px = (x1 - x0) / 2 + mPadding + mPaddingLeft;
//        float py = (y1 - y0) / 2 + mPadding + mPaddingTop;
//        canvas.rotate(150f);//旋转
//        canvas.rotate(startAngle, px, py);

        //设置显示的时候保留两位小数
        DecimalFormat mFormat = new DecimalFormat("##0");
        if (isDecimal) {
            mFormat = new DecimalFormat("##0.00");
        }
        if (leftMsg == null) {
            leftMsg = "";
        }
        if (rightMsg == null) {
            rightMsg = "";
        }
        //设置文字
        String msg = leftMsg + mFormat.format(msgSize) + rightMsg;
        if (tv != null) {
            tv.setText(msg);
        }
        if (isRefresh) {
            setData();
        }
    }

    /**
     * 数据处理
     */
    private void setData() {
        //判断当前数值是否超过设置的最大值，简单点就是判断当前值最后的角度是否会超过最大角度
        if (size >= maxSize) {
            if (msgSize >= maxSize && msgSize < size) {
                number = maxSize;
                msgSize = msgSize + proportionSize;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else if (msgSize == size) {
                number = maxSize;
                msgSize = size;
                isRefresh = false;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else if (msgSize > (size + proportionSize)) {
                msgSize = msgSize - proportionSize;
                number = maxSize;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else if (msgSize > size && msgSize < (size + proportionSize)) {
                //当进度计算过头归为填入数值
                msgSize = size;
                number = maxSize;
                isRefresh = false;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else {
                msgSize = msgSize + proportionSize;
                number = msgSize;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            }
        } else if (size >= minSize) {
            //判断当前增加的角度是否超过数值对应的角度
            if (msgSize < size) {
                msgSize = msgSize + proportionSize;
                number = msgSize;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else if (msgSize == size) {
                msgSize = size;
                number = msgSize;
                isRefresh = false;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else if (msgSize > size && msgSize < (size + proportionSize)) {
                msgSize = size;
                number = msgSize;
                isRefresh = false;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            } else {
                msgSize = msgSize - proportionSize;
                number = msgSize;
                //计算当前值对应的角度
                mSweepAngle = (number - minSize) * proportion;
                invalidate();
            }
        } else {
            msgSize = size;
            number = minSize;
            isRefresh = false;
            //计算当前值对应的角度
            mSweepAngle = (number - minSize) * proportion;
            invalidate();
        }
    }

    /**
     * MeasureSpec.EXACTLY是精确尺寸
     * MeasureSpec.AT_MOST是最大尺寸
     * MeasureSpec.UNSPECIFIED是未指定尺寸
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取宽度的模式与大小
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);

        //获取高度的模式与大小
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//        int widthSize = measureWidth(widthMode, width);
//        int heightSize = measureHeight(heightMode, height);
        if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
            mWidth = DisplayUtils.dip2px(getContext(), 100f);
        } else {
            mWidth = widthSpecSize;
        }
        if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
            mHeight = DisplayUtils.dip2px(getContext(), 100f);
        } else {
            mHeight = heightSpecSize;
        }
        if (isEquilateral) {
            if (mWidth >= mHeight) {
                setMeasuredDimension(mHeight, mHeight);
            } else {
                setMeasuredDimension(mWidth, mWidth);
            }
        } else {
            setMeasuredDimension(mWidth, mHeight);
        }
    }

    /**
     * 判断宽度
     *
     * @param mode  宽度模式
     * @param width 宽度
     */
    private int measureWidth(int mode, int width) {
        int mWidth = DisplayUtils.getWindowWidth(mContext) / 5 * 3;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                mWidth = width;
                break;
            default:
                break;
        }
        return mWidth;
    }

    /**
     * 判断高度
     *
     * @param mode   高度模式
     * @param height 高度
     */
    private int measureHeight(int mode, int height) {
        int mHeight = DisplayUtils.getWindowWidth(mContext) / 5 * 3;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                mHeight = height;
                break;
            default:
                break;
        }
        return mHeight;
    }

    /**
     * 设置最大值
     *
     * @param maxSize 最大值
     */
    public CircleProgress setMaxSize(float maxSize) {
        this.maxSize = maxSize;
        //计算值为1时所占角度的大小
        this.proportion = this.angle / (this.maxSize - this.minSize);
        this.proportionSize = this.maxSize / 60;
        return this;
    }

    /**
     * 设置最小值
     *
     * @param minSize 最小值
     */
    public CircleProgress setMinSize(float minSize) {
        this.minSize = minSize;
        this.number = minSize;
        //计算值为1时所占角度的大小
        this.proportion = this.angle / (this.maxSize - this.minSize);
        return this;
    }

    /**
     * 设置渐变颜色
     *
     * @param colors 颜色数组
     */
    public CircleProgress setColors(int[] colors) {
        this.colors = colors;
        return this;
    }

    /**
     * 起始点位置
     *
     * @param startAngle 多少度处（默认150°）
     */
    public CircleProgress setStartAngle(float startAngle) {
        this.startAngle = startAngle;
        return this;
    }

    /**
     * 设置圆环显示大小，最大360°
     *
     * @param angle 度数（默认240）
     */
    public CircleProgress setAngle(float angle) {
        this.angle = angle;
        return this;
    }

    /**
     * 设置是否需要颜色渐变
     *
     * @param isShader 默认为true，需要
     */
    public CircleProgress isShader(boolean isShader) {
        this.isShader = isShader;
        return this;
    }

    /**
     * 设置中间圆背景颜色
     *
     * @param rColor 默认透明
     */
    public CircleProgress setRoundBgColor(int rColor) {
        this.rColor = rColor;
        return this;
    }

    /**
     * 设置圆环画笔颜色
     *
     * @param defaultColor 颜色,默认为红色
     */
    public CircleProgress setDefaultColor(int defaultColor) {
        this.defaultColor = defaultColor;
        return this;
    }

    /**
     * 设置圆环画笔线宽
     *
     * @param defaultWidth 圆环画笔线宽，默认为16px
     */
    public CircleProgress setDefaultWidth(float defaultWidth) {
        this.defaultWidth = defaultWidth;
        return this;
    }

    /**
     * 设置背景圆环画笔颜色
     *
     * @param bgColor 背景圆环颜色，默认灰色
     */
    public CircleProgress setBgColor(int bgColor) {
        this.bgColor = bgColor;
        return this;
    }

    /**
     * 设置背景圆环线宽
     *
     * @param bgWidth 背景圆环线宽，默认16px
     */
    public CircleProgress setBgWidth(float bgWidth) {
        this.bgWidth = bgWidth;
        return this;
    }

    /**
     * 设置左边文本
     *
     * @param leftMsg 文本
     */
    public CircleProgress setLeftMsg(String leftMsg) {
        this.leftMsg = leftMsg;
        return this;
    }

    /**
     * 设置右边文本
     *
     * @param rightMsg 文本
     */
    public CircleProgress setRightMsg(String rightMsg) {
        this.rightMsg = rightMsg;
        return this;
    }

    /**
     * 设置是否显示小数
     *
     * @param isDecimal 默认显示
     */
    public CircleProgress isDecimal(boolean isDecimal) {
        this.isDecimal = isDecimal;
        return this;
    }

    /**
     * 设置数值
     *
     * @param number 数值
     */
    public void setNumber(float number, TextView textView) {
        this.tv = textView;
        if (number == size) {
            return;
        }
        size = number;
        if (size >= maxSize) {
            size = maxSize;
        } else if (size <= minSize) {
            size = minSize;
        }
        msgSize = number;
        this.number = size;
        //计算当前值对应的角度
        this.mSweepAngle = (this.number - this.minSize) * this.proportion;
        isRefresh = false;
        postInvalidate();
    }

    /**
     * 设置数值
     *
     * @param number 数值
     */
    public void setNumber(float number) {
        this.tv = null;
        if (number == size) {
            return;
        }
        size = number;
        if (size >= maxSize) {
            size = maxSize;
        } else if (size <= minSize) {
            size = minSize;
        }
        msgSize = number;
        this.number = size;
        //计算当前值对应的角度
        this.mSweepAngle = (this.number - this.minSize) * this.proportion;
        isRefresh = false;
        postInvalidate();
    }

    /**
     * 用于需要长时间才会变化进度，有渐进动画效果
     *
     * @param number 数值
     */
    public void setLongTimeNumber(float number) {
        this.tv = null;
        if (number == size) {
            return;
        }
        size = number;
        isRefresh = true;
        invalidate();
    }

    /**
     * 用于需要长时间才会变化进度，有渐进动画效果
     *
     * @param number 数值
     */
    public void setLongTimeNumber(float number, TextView textView) {
        this.tv = textView;
        if (number == size) {
            return;
        }
        size = number;
        isRefresh = true;
        invalidate();
    }

    /**
     * 返回是否等边
     */
    public boolean isEquilateral() {
        return isEquilateral;
    }

    /**
     * 设置是否等边
     */
    public void setEquilateral(boolean equilateral) {
        isEquilateral = equilateral;
    }
}
